package net.slique.sf5.model.toys.junk;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang.StringUtils;

import net.slique.sf5.model.silverware.ComputationalModel;
import net.slique.sf5.model.silverware.ModelInformation;
import net.slique.sf5.model.silverware.ModelMeta;
import net.slique.sf5.model.silverware.OkPredicateResponse;
import net.slique.sf5.model.silverware.Solution;
import net.slique.sf5.model.silverware.SolutionResponse;

public class JunkModel implements ComputationalModel {
	
	/**
	 * Quantity of numbers to genenrate.
	 */
	private int quantity = 250;
	
	/**
	 * Model solution payload. 
	 */
	private List<Integer> payload = new ArrayList<Integer>();
	
	@Override
	public ModelInformation getInformation() {
		ModelInformation modelInformation = new ModelInformation();
		modelInformation.setName("Random Number Generator").setLanguage("Java").setVersion("1.0");
		modelInformation.setProvider(this.getClass().getName());
		modelInformation.getParameters().add(new ModelMeta().setProperty("quantity").setValue(Integer.toString(getQuantity())).setDescription("Quantity"));

		StringBuilder desc = new StringBuilder("Framework testing model that generates random numbers.  ");
		desc.append("Model used to test framework's handling of preconditions, run-time exceptions, malformed responses, interruptions, and postconditions.<br><br>");
		desc.append("If the quantity:<br>");		
		desc.append("= -2: preSolve will return null<br>");
		desc.append("= -1: preSolve will throw a runtime exception<br>");
		desc.append("= 0: preSolve will be set to false.<br>");
		desc.append("= 1: preSolve will be set to true without a message; null solution response.<br>");
		desc.append("= 2: preSolve will be set to true with a message; null solution response.<br>");
		desc.append("<= 0: solve will throw a runtime exception<br>");
		desc.append("= 3: solve will return an empty solution response.<br>");
		desc.append("= 4: solve will return a response with a null solution.<br>");
		desc.append("5 <= q < 100: solve will return only data payload.<br>");
		desc.append("100 <= q <= 200: solve will return only plot payload.<br>");
		desc.append("> 200: solve will return both data and plot payload.<br>");
		
		modelInformation.setDescription(desc.toString());				
		return modelInformation;
	}

	@Override
	public OkPredicateResponse postSolve() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public OkPredicateResponse preSolve() {
		OkPredicateResponse retval = new OkPredicateResponse();
		switch(getQuantity()) {
			case -2:
				return null;
			case -1:
				throw new RuntimeException("Generator presolve runtime exception for quantity: " + -1);
			case 0:
				retval.setOk(false);
				retval.setMessage("Generator error: aarghghablharlahglhrggg");
				break;
			case 1:
				retval.setOk(true);
				retval.setMessage(null);
				break;
			case 2:
			default:
				retval.setOk(true);
				retval.setMessage("OK");
				break;
		}
		return retval;
	}

	@Override
	public SolutionResponse solve() {
		SolutionResponse solutionResponse = null;
		if(getQuantity() <= 0) {
			throw new RuntimeException("Unable to generate non-positve quantity of random numbers.");
		}
		switch(getQuantity()) {
			case 1:
			case 2:
				solutionResponse = null;
				break;
			case 3:
				solutionResponse = new SolutionResponse();
				break;
			case 4:
				solutionResponse = new SolutionResponse();
				solutionResponse.getSolutions().add(null);
				break;
			default:
				Random random = new Random();
				for(int i = 0; i < getQuantity(); i++) {
					payload.add(random.nextInt());
				}
				solutionResponse = new SolutionResponse();
				Solution solution = new Solution();
				if(getQuantity() >= 5 &&  getQuantity() < 100) {
					solution.setData(StringUtils.join(payload, "\n"));
				}
				else if (getQuantity() >= 100 && getQuantity() <= 200) {
					solution.setPlot(makePlot());
				}
				else {
					solution.setData(StringUtils.join(payload, "\n"));
					solution.setPlot(makePlot());
				}
				solutionResponse.getSolutions().add(solution);
		}
		return solutionResponse;
	}

	private String makePlot() {
		StringBuilder plotUrl = new StringBuilder("http://chart.apis.google.com/chart?chs=500x500&cht=qr&chl=");
		plotUrl.append(StringUtils.join(payload, ""));
		if(plotUrl.length() > 2000) {
			plotUrl.setLength(2000);
		}
		return plotUrl.toString();
	}

	/**
	 * @return the quantity
	 */
	public int getQuantity() {
		return quantity;
	}

	/**
	 * @param quantity the quantity to set
	 */
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
	
	

}
